package com.ynb.lighterbuffer;

import java.io.IOException;
import java.nio.charset.Charset;

public abstract class BinaryWriter {

	private Charset utf8 = Charset.forName("utf8");

	public abstract void writeByte(byte n) throws IOException;

	public abstract void writeBytes(byte[] datas) throws IOException;

	public abstract byte[] toArray() throws IOException;

	public void writeBool(boolean b) throws IOException {
		writeByte((byte) (b ? 1 : 0));
	}

	public void writeShort(short n) throws IOException {
		writeByte((byte) n);
		writeByte((byte) (n >>> 8));
	}

	public void writeInt(int n) throws IOException {
		if (n >= 0) {
			if ((n & ~0b00111111) == 0) {
				writeByte((byte) (n | 0b01000000));
			} else {
				writeByte((byte) (n | 0b11000000));
				n >>>= 6;
				while (true) {
					if ((n & ~0b01111111) == 0) {
						writeByte((byte) n);
						return;
					} else {
						writeByte((byte) (n | 0b10000000));
						n >>>= 7;
					}
				}
			}
		} else {
			if ((~n & ~0b111111) == 0) {
				writeByte((byte) (n & 0b00111111));
			} else {
				writeByte((byte) ((n & 0b00111111) | 0b10000000));
				n >>= 6;
				while (true) {
					if ((~n & ~0b1111111) == 0) {
						writeByte((byte) (n & 0b01111111));
						return;
					} else {
						writeByte((byte) ((n & 0b01111111) | 0b10000000));
						n >>= 7;
					}
				}
			}
		}
	}

	public void writeLong(long n) throws IOException {
		if (n >= 0) {
			if ((n & ~0b00111111) == 0) {
				writeByte((byte) (n | 0b01000000));
			} else {
				writeByte((byte) (n | 0b11000000));
				n >>>= 6;
				while (true) {
					if ((n & ~0b01111111) == 0) {
						writeByte((byte) n);
						return;
					} else {
						writeByte((byte) (n | 0b10000000));
						n >>>= 7;
					}
				}
			}
		} else {
			if ((~n & ~0b111111) == 0) {
				writeByte((byte) (n & 0b00111111));
			} else {
				writeByte((byte) ((n & 0b00111111) | 0b10000000));
				n >>= 6;
				while (true) {
					if ((~n & ~0b1111111) == 0) {
						writeByte((byte) (n & 0b01111111));
						return;
					} else {
						writeByte((byte) ((n & 0b01111111) | 0b10000000));
						n >>= 7;
					}
				}
			}
		}
	}

	public void writeFloat(float n) throws IOException {
		int value = Float.floatToRawIntBits(n);
		writeByte((byte) value);
		writeByte((byte) (value >>> 8));
		writeByte((byte) (value >>> 16));
		writeByte((byte) (value >>> 24));
	}

	public void writeDouble(double n) throws IOException {
		long value = Double.doubleToRawLongBits(n);
		writeByte((byte) value);
		writeByte((byte) (value >>> 8));
		writeByte((byte) (value >>> 16));
		writeByte((byte) (value >>> 24));
		writeByte((byte) (value >>> 32));
		writeByte((byte) (value >>> 40));
		writeByte((byte) (value >>> 48));
		writeByte((byte) (value >>> 56));
	}

	public void writeChar(char c) throws IOException {
		writeInt(c);
	}

	public void writeString(String str) throws IOException {
		if (str != null) {
			if (str.length() > 0) {
				byte[] data = str.getBytes(utf8);
				writeInt(data.length);
				writeBytes(data);
			} else {
				writeInt(0);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeShortArr(short[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (short n : arr) {
				writeShort(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeShortArr(Short[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (short n : arr) {
				writeShort(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeIntArr(int[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (int n : arr) {
				writeInt(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeIntArr(Integer[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (int n : arr) {
				writeInt(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeLongArr(long[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (long n : arr) {
				writeLong(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeLongArr(Long[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (long n : arr) {
				writeLong(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeFloatArr(float[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (float n : arr) {
				writeFloat(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeFloatArr(Float[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (float n : arr) {
				writeFloat(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeDoubleArr(double[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (double n : arr) {
				writeDouble(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeDoubleArr(Double[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (double n : arr) {
				writeDouble(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeBoolArr(boolean[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (boolean n : arr) {
				writeBool(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeBoolArr(Boolean[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (boolean n : arr) {
				writeBool(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeStringArr(String[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (String n : arr) {
				writeString(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeCharArr(char[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (char n : arr) {
				writeChar(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeCharArr(Character[] arr) throws IOException {
		if (arr != null) {
			writeInt(arr.length);
			for (char n : arr) {
				writeChar(n);
			}
		} else {
			writeInt(-1);
		}
	}

	public void writeNull(boolean isNull) throws IOException{
		writeBool(isNull);
	}
	
}
